/*
Project : Programmable Control of Airflow System for Maintaining Oxygen Saturation in Pre-term infant 
Microcontroller : STM32F4 Discovery (STM32F407VG)
File : example1.c
Deverloper : Phattaradanai Kiratiwudhikul
Reseach & Deverloped by Department of Electrical Engineering, Faculty of Engineering, Mahidol University
*/
//------------------------------------------------------------------------------
#include "FreeRTOS.h"
#include "freeRTOS_priority.h"

#include "semphr.h"
#include "task.h"
#include "timers.h"
#include "queue.h"

#include "stdio.h"
#include <stdlib.h>
#include "misc.h"
#include "stm32f4xx_usart.h"
#include "stm32f4_discovery.h"
#include "stm32f4xx.h"
#include "system_stm32f4xx.h"
#include "stm32f4xx_it.h"
#include "stm32f4xx_conf.h"
#include "stm32f4xx_rcc.h"
#include "stm32f4xx_gpio.h"
#include "stm32f4xx_tim.h"
//------------------------------------------------------------------------------
#define mainDELAY_LOOP_COUNT 1000
#define QueueSize 5
//------------------------------------------------------------------------------
void driver_usart_setup(void);
void vTask1 (void * pvParameters);
void vTask2 (void * pvParameters);
//------------------------------------------------------------------------------
char Buffer[5];
uint8_t time = 0;
xTaskHandle  xTask2Handle;
xTaskHandle  xTask1Handle;

xQueueHandle *xQueue;
xSemaphoreHandle ISR_semaphore = NULL;

uint8_t uiTask1Priority, uiTask2Priority;
//------------------------------------------------------------------------------
int main (void)
{   
  driver_usart_setup();                                                         // Config USART 3
  
  /* Create Queue */
  xQueue = xQueueCreate(QueueSize, sizeof(char *));
  
  /* Create Binary Semaphore */
  vSemaphoreCreateBinary( ISR_semaphore );
  
  /* Create Task RTOS */
  if(xTaskCreate(vTask1, (signed char *) "Task 1" , 5000, NULL, 1, xTask1Handle) != pdPASS)
  {
    printf("Create Task 1 fail\r\n");
  }
  else 
  {
    printf("Create Task 1 suscess\r\n");
    uiTask1Priority = uxTaskPriorityGet(xTask1Handle);
  }
  if(xTaskCreate(vTask2,(signed char *) "Task 2" , 5000, NULL, 5, xTask2Handle) != pdPASS)
  {
    printf("Create Task 2 fail\r\n");
  }
  else 
  {
    printf("Create Task 2 suscess\r\n");
    uiTask2Priority = uxTaskPriorityGet(xTask2Handle);
  }
  
  /* Start scheduler */
  vTaskStartScheduler();
  
  /* We should never get here as control is now taken by the scheduler */
  for( ;; );
}
//------------------------------------------------------------------------------
void vTask1 (void * pvParameters)
{
  //const char *pcTaskName = "Task 1 (one) is running\r\n";
  volatile uint32_t ul;
 
  for(;;)
  {
//    printf(pcTaskName);
//    printf("Task 1 (one) is running\r\n");
    
//    vTaskDelay(500 / portTICK_RATE_MS);
    xSemaphoreTake( ISR_semaphore, portMAX_DELAY );
    vTaskPrioritySet( xTask1Handle, 1);
    uiTask1Priority = uxTaskPriorityGet(xTask1Handle);
    printf("Operating ......\r\n");

  }
  
}
//------------------------------------------------------------------------------
void vTask2 (void * pvParameters)
{
 // const char *pcTaskName = "Task 2 (two) is running\r\n";
  volatile uint32_t ul;
  portBASE_TYPE xStatus;
  char cReceiveValue[sizeof(Buffer)];
  
  for(;;)
  {
//    printf(pcTaskName);
//    printf("Task 2 (two) is running\r\n");
    xStatus = xQueueReceive(xQueue, &cReceiveValue, 500/portTICK_RATE_MS );
    
    if(xStatus == pdPASS )
    {
      printf("Queue Receive Already.\r\n");
    }
    vTaskDelay(250 / portTICK_RATE_MS);
    vTaskPrioritySet( xTask2Handle, 3);
    uiTask2Priority = uxTaskPriorityGet(xTask2Handle);
  }
}

//------------------------------------------------------------------------------
void driver_usart_setup(void)
{
  GPIO_InitTypeDef GPIO_InitStruct;
  USART_InitTypeDef USART_InitStruct;
	
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
	
  /*
    Use Port D Pin PD8 Tx
    Use Port D Pin PD9 Rx
  */
  /* set GPIO init structure parameters values */
  GPIO_InitStruct.GPIO_Pin  = GPIO_Pin_8 | GPIO_Pin_9;
  GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
  GPIO_Init(GPIOD, &GPIO_InitStruct);
  
  /* Connect PXx to USARTx_Tx*/
  GPIO_PinAFConfig(GPIOD, GPIO_PinSource8, GPIO_AF_USART3);
  /* Connect PXx to USARTx_Rx*/
  GPIO_PinAFConfig(GPIOD, GPIO_PinSource9, GPIO_AF_USART3);
  
  
  /* USART_InitStruct members default value */
  USART_InitStruct.USART_BaudRate = 115200;
  USART_InitStruct.USART_WordLength = USART_WordLength_8b;
  USART_InitStruct.USART_StopBits = USART_StopBits_1;
  USART_InitStruct.USART_Parity = USART_Parity_No;
  USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
  USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;  
  USART_Init(USART3, &USART_InitStruct);
  
  /*USART Interrupt*/
  /* Set interrupt: NVIC_Setup */
  NVIC_InitTypeDef NVIC_InitStruct;
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
  //ENABLE USART3 Interruper
  NVIC_InitStruct.NVIC_IRQChannel = USART3_IRQn;
  NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStruct);

  /* Set Interrupt Mode*/ 
  USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);                                //ENABLE the USART Receive Interrupt

  USART_Cmd(USART3, ENABLE);                                                    //Enable USART3
}
//------------------------------------------------------------------------------
void USART3_IRQHandler(void)
{
  static portBASE_TYPE xHigherPriorityTaskWoken = 7;
  portBASE_TYPE xStatus_semaphore;
  
  if(USART_GetITStatus(USART3, USART_IT_RXNE) == SET)
  {
    Buffer[time++] = USART_ReceiveData(USART3);  
    
    if(time > QueueSize)
    {
      time = 0;
      xQueueSend(xQueue, &Buffer, portMAX_DELAY);
      xSemaphoreGive(ISR_semaphore);                                            // Give Semaphore
    }
  }
  USART_ClearITPendingBit(USART3, USART_IT_RXNE);
}
//------------------------------------------------------------------------------
void vApplicationTickHook(void)
{
 
}
//------------------------------------------------------------------------------
void vApplicationStackOverflowHook( xTaskHandle *pxTask, signed char *pcTaskName )
{
	( void ) pcTaskName;
	( void ) pxTask;

	/* Run time stack overflow checking is performed if
	configCHECK_FOR_STACK_OVERFLOW is defined to 1 or 2.  This hook
	function is called if a stack overflow is detected. */
	taskDISABLE_INTERRUPTS();
	for( ;; );
}
//------------------------------------------------------------------------------
void vApplicationMallocFailedHook(void)
{
  //taskDISABLE_INTERRUPTS();
  while(1);
}
//------------------------------------------------------------------------------
// Function can use printf(); in sent data
int fputc(int ch, FILE *f)
{
  /* Place your implementation of fputc here */
  /* e.g. write a character to the USART */
  USART_SendData(USART3, (uint8_t) ch);
  /* Loop until the end of transmission */
  while (USART_GetFlagStatus(USART3, USART_FLAG_TC) == RESET)
  {}
  return ch;
}
//------------------------------------------------------------------------------
#ifdef USE_FULL_ASSERT
/**
* @brief  assert_failed
*         Reports the name of the source file and the source line number
*         where the assert_param error has occurred.
* @param  File: pointer to the source file name
* @param  Line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t* file, uint32_t line)
{
  /* User can add his own implementation to report the file name and line number,
  ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
 
  /* Infinite loop */
  while (1)
  {}
}
#endif
